// Ch3_2.cpp : Initialization functions

// CH3_2.cpp
// by Charles Mc Auley
// "Programming AutoCAD 2000 with ObjectARX"
//
// This application demonstrates the use of selection
// sets. The user is asked to select a set of entities
// and then asked to select a target entity whose layer
// we extract, after which we move the entities in the selection
// set to the target layer. We use result buffers to
// modify the entites in the selection set.
// This application represents the old style methods for
// mainpulating AutoCAD entities and these method has been
// superceded by ObjectARX.
//
/////////////////////////////////////////////////////////


#include "StdAfx.h"
#include "StdArx.h"
#include "resource.h"

HINSTANCE _hdllInstance =NULL ;

// This command registers an ARX command.
void AddCommand(const char* cmdGroup, const char* cmdInt, const char* cmdLoc,
				const int cmdFlags, const AcRxFunctionPtr cmdProc, const int idLocal = -1);

// NOTE: DO NOT edit the following lines.
//{{AFX_ARX_MSG
void InitApplication();
void UnloadApplication();
//}}AFX_ARX_MSG

// NOTE: DO NOT edit the following lines.
//{{AFX_ARX_ADDIN_FUNCS
//}}AFX_ARX_ADDIN_FUNCS

/////////////////////////////////////////////////////////////////////////////
// DLL Entry Point
extern "C"
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/)
{
	if (dwReason == DLL_PROCESS_ATTACH)
	{
        _hdllInstance = hInstance;
	} else if (dwReason == DLL_PROCESS_DETACH) {
	}
	return TRUE;    // ok
}



/////////////////////////////////////////////////////////////////////////////
// ObjectARX EntryPoint
extern "C" AcRx::AppRetCode 
acrxEntryPoint(AcRx::AppMsgCode msg, void* pkt)
{
	switch (msg) {
	case AcRx::kInitAppMsg:
		// Comment out the following line if your
		// application should be locked into memory
		acrxDynamicLinker->unlockApplication(pkt);
		acrxDynamicLinker->registerAppMDIAware(pkt);
		InitApplication();
		break;
	case AcRx::kUnloadAppMsg:
		UnloadApplication();
		break;
	}
	return AcRx::kRetOK;
}


// Init this application. Register your
// commands, reactors...
void InitApplication()
{
	// NOTE: DO NOT edit the following lines.
	//{{AFX_ARX_INIT
	AddCommand("CH3_APPS", "CEL", "CEL", ACRX_CMD_MODAL, cel);
	//}}AFX_ARX_INIT

	// TODO: add your initialization functions
	// CEL = Change Entities Layer
	acutPrintf("Enter \"CEL\" at the command prompt to execute.\n");
}

// Unload this application. Unregister all objects
// registered in InitApplication.
void UnloadApplication()
{
	// NOTE: DO NOT edit the following lines.
	//{{AFX_ARX_EXIT
	acedRegCmds->removeGroup("CH3_APPS");
	//}}AFX_ARX_EXIT

	// TODO: clean up your application
	acutPrintf("%s%s", "Goodbye\n", "Removing command group \"CH3_APPS\"\n");
}

// This functions registers an ARX command.
// It can be used to read the localized command name
// from a string table stored in the resources.
void AddCommand(const char* cmdGroup, const char* cmdInt, const char* cmdLoc,
				const int cmdFlags, const AcRxFunctionPtr cmdProc, const int idLocal)
{
	char cmdLocRes[65];

	// If idLocal is not -1, it's treated as an ID for
	// a string stored in the resources.
	if (idLocal != -1) {

		// Load strings from the string table and register the command.
		::LoadString(_hdllInstance, idLocal, cmdLocRes, 64);
		acedRegCmds->addCommand(cmdGroup, cmdInt, cmdLocRes, cmdFlags, cmdProc);

	} else
		// idLocal is -1, so the 'hard coded'
		// localized function name is used.
		acedRegCmds->addCommand(cmdGroup, cmdInt, cmdLoc, cmdFlags, cmdProc);
}


// User defined functin called by
// cel() see Ch3_2Commands.cpp
void chgEntsLyr(ads_name ent, ads_name ss)
{
	long idx;					// Index of the selection set marker
	long lenSS;					// Length of selection set
	char lyrName[32];			// Target layer name - max length of layer name = 31
	ads_name ssEntName;			// Entity name in the selection set
	struct resbuf *rbTargEnt;	// resbuf to hold ent data
	struct resbuf *rbSSEnt;		// resbuf of selection set entity
	struct resbuf *rbTrav;		// resbuf to traverse linked list
	int rc;						// Return code

	// Get the layer name of the target entity
	rbTargEnt = acdbEntGet(ent);
	if(!rbTargEnt)
	{
		acutPrintf("\nFailed to get target entities data. ");
		return;
	}

	rbTrav = rbTargEnt;	// Make rbTrav point to rbTargEnt

	while(rbTrav)
	{
		switch(rbTrav->restype)
		{
			case 8 : // DXF code for layer name
				strcpy(lyrName, rbTrav->resval.rstring);
			break;
		}//switch
		// I could have used an if statement
		// here as I'm only serching for one
		// item, but when I'm dealing with
		// resbuf's I prefer to use a switch
		// statement.

		rbTrav = rbTrav->rbnext;

	}//while

	// We dont need the rbTargEnt resbuf anymore
	// so release it - dont forget

	if(rbTargEnt)
	{
		acutRelRb(rbTargEnt);
	}

	// Now we are going to traverse the selection set
	// changing each entity to the target layer. Check
	// to see if its not an empty selection set

	rc = acedSSLength(ss, &lenSS);	// Note: we pass the address of lenSS
	if(rc != RTNORM)
	{
		acutPrintf("\nInvalid or empty selection set. ");
		return;
	}
	
	for(idx = 0; idx < lenSS; idx++)
	{
		// Get the entity name at the spcified index
		rc = acedSSName(ss, idx, ssEntName);
		if(rc != RTNORM)
		{
			break;
		}

		// Get ssEntName entity data
		rbSSEnt = acdbEntGet(ssEntName);
		if(!rbSSEnt)
		{
			break;
		}

		rbTrav = rbSSEnt;	// Make rbTrav point to rbSSEnt

		// Now that we have a linked list resbuf
		// change the DXF 8 field to the target
		// layer name.

		while(rbTrav)
		{
			switch(rbTrav->restype)
			{
				case 8 : // DXF code for layer name
					strcpy(rbTrav->resval.rstring, lyrName);
				break;
			}//switch

			rbTrav = rbTrav->rbnext;

		}//while

		// Now we need to modify the entity
		// with the changed resbuf
		rc = acdbEntMod(rbSSEnt);
		if(rc != RTNORM)
		{
			acutPrintf("\nFailed to modify the entity ");
		}

		// Release the resbuf
		if(rbSSEnt)
		{
			acutRelRb(rbSSEnt);
		}

	}//for
}